package com.yaxin.outsourcing.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yaxin.common.core.domain.PageQuery;
import com.yaxin.common.core.domain.entity.SysDept;
import com.yaxin.common.core.page.TableDataInfo;
import com.yaxin.common.utils.JsonUtils;
import com.yaxin.common.utils.redis.RedisUtils;
import com.yaxin.mq.producer.NormalRabbitProducer;
import com.yaxin.outsourcing.domain.HrMessage;
import com.yaxin.outsourcing.domain.vo.AccessApplicationVO;
import com.yaxin.outsourcing.domain.dto.AccessApplicationDTO;
import com.yaxin.outsourcing.domain.po.AccessApplication;
import com.yaxin.outsourcing.domain.po.OutsourcingPerson;
import com.yaxin.outsourcing.domain.vo.AccessApplicationDetailVO;
import com.yaxin.outsourcing.domain.vo.OutsourcingPersonMsgVO;
import com.yaxin.outsourcing.enums.AppStatus;
import com.yaxin.outsourcing.mapper.AccessApplicationMapper;
import com.yaxin.outsourcing.mapper.OutsourcingPersonMapper;
import com.yaxin.outsourcing.service.IAccessApplicationService;
import com.yaxin.system.mapper.SysDeptMapper;
import com.yaxin.system.service.ISysDeptService;
import com.yaxin.system.service.ISysOssService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.awt.image.BufferedImage;


/**
 * <p>
 * 外协人员信息表 服务实现类
 * </p>
 *
 * @author zcc
 * @since 2025-07-29
 */


@Service
public class AccessApplicationServiceImpl extends ServiceImpl<AccessApplicationMapper, AccessApplication> implements IAccessApplicationService {

    @Autowired
    private AccessApplicationMapper accessApplicationMapper;
    @Autowired
    private OutsourcingPersonMapper outsourcingPersonMapper;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private NormalRabbitProducer normalRabbitProducer;
    @Autowired
    private ISysOssService sysOssService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteApplication(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new IllegalArgumentException("ID列表不能为空");
        }

        // 1. 批量删除关联的外协人员
        outsourcingPersonMapper.update(null,
            new LambdaUpdateWrapper<OutsourcingPerson>()
                .in(OutsourcingPerson::getAppId, ids)
                .set(OutsourcingPerson::getIsDeleted, 2)
                .set(OutsourcingPerson::getUpdateTime, LocalDateTime.now())
        );

        // 2. 批量更新申请单（改用 updateWrapper）
        boolean isSuccess = update(null,
            new LambdaUpdateWrapper<AccessApplication>()
                .in(AccessApplication::getId, ids)
                .set(AccessApplication::getIsDeleted, 2)
                .set(AccessApplication::getUpdateTime, LocalDateTime.now())
        );

        if (!isSuccess) {
            throw new RuntimeException("更新申请单失败，请检查ID是否存在");
        }
    }

    @Override
    public void deletePerson(String appNo) {
        // 1. 查询申请单
        LambdaQueryWrapper<AccessApplication> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AccessApplication::getAppNo, appNo);
        AccessApplication application = getOne(queryWrapper);
        if (application == null) {
            throw new RuntimeException("申请单不存在");
        }

        // 2. 批量更新关联的外协人员，将逻辑删除状态设置为2
        outsourcingPersonMapper.update(null,
            new LambdaUpdateWrapper<OutsourcingPerson>()
                .eq(OutsourcingPerson::getAppId, application.getId())
                .set(OutsourcingPerson::getIsDeleted, 2)
                .set(OutsourcingPerson::getUpdateTime, LocalDateTime.now())
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int createApplication(AccessApplicationDTO dto) {
        // 构建实体对象
        AccessApplication entity = new AccessApplication();
        // 1. 校验外协单位是否存在
        SysDept dept1 = sysDeptMapper.selectOne(
            new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getDeptName, dto.getOutUnit())
                .last("LIMIT 1")
        );
        // 2. 校验申请单位是否存在
        SysDept dept2 = sysDeptMapper.selectOne(
            new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getDeptName, dto.getAppUnit())
                .last("LIMIT 1")
        );
        if (dept1 == null || dept2 == null) {
//            throw new ServiceException("外协单位【" + dto.getOutUnit() + "】不存在，请先在组织架构中维护");
            System.out.println("======数据库待完善，申请单位或外协单位缺失======");
        }
        BeanUtil.copyProperties(dto, entity);
        entity.setOutUid(dept1.getDeptId());
        entity.setAppUid(dept2.getDeptId());
        entity.setAppDate(LocalDate.parse(LocalDate.now().toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        entity.setStatus(AppStatus.NEW.getValue());
        // 保存到数据库
        return accessApplicationMapper.insert(entity);
    }

    @Override
    public AccessApplicationDetailVO getApplicationDetail(Long id) {
        // 1. 查询申请单信息
        AccessApplication application = getById(id);
        if (application == null) {
            throw new RuntimeException("申请单不存在");
        }

        // 2. 转换为VO对象
        AccessApplicationDetailVO detailVO = new AccessApplicationDetailVO();
        BeanUtils.copyProperties(application, detailVO);

        return detailVO;
    }

    @Override
    public void updateApplication(Long id, AccessApplicationDTO dto) {
        // 1. 先查询现有记录
        AccessApplication existingEntity = getById(id);
        if (existingEntity == null) {
            throw new RuntimeException("申请单不存在");
        }

        // 2. 处理app_uid: 如果app_unit变更，则重新获取或生成app_uid
        Long appUid = existingEntity.getAppUid(); // 保留原有app_uid
        if (!dto.getAppUnit().equals(existingEntity.getAppUnit())) {
            // 如果申请单位变更，则重新查找或生成app_uid
            appUid = accessApplicationMapper.selectAppUidByAppUnit(dto.getAppUnit());
            if (appUid == null) {
                appUid = System.currentTimeMillis() + (long)(Math.random() * 1000);
            }
        }

        // 3. 处理out_uid: 如果out_unit变更，则重新获取或生成out_uid
        Long outUid = existingEntity.getOutUid(); // 保留原有out_uid
        if (!dto.getOutUnit().equals(existingEntity.getOutUnit())) {
            // 如果外协单位变更，则重新查找或生成out_uid
            outUid = accessApplicationMapper.selectOutUidByOutUnit(dto.getOutUnit());
            if (outUid == null) {
                outUid = System.currentTimeMillis() + (long)(Math.random() * 1000);
            }
        }

        // 4. 更新实体对象（只更新变更字段）
//        existingEntity
//                .setAppUnit(dto.getAppUnit())
//                .setAppPerson(dto.getAppPerson())
//                .setEntryCount(dto.getEntryCount())
//                .setOutUnit(dto.getOutUnit())
//                .setArea(dto.getArea())
//                .setOutContact(dto.getOutContact())
//                .setOutPhone(dto.getOutPhone())
//                .setContent(dto.getContent())
//                .setAppUid(appUid)  // 更新app_uid
//                .setOutUid(outUid)  // 更新out_uid
//                .setStatus(AppStatus.NEW.getValue()) // 0-新建
//                .setUpdataBy(dto.getAppPerson())
//                .setUpdateTime(LocalDateTime.now()); // 只更新修改时间，不更新创建时间

        // 5. 更新到数据库
        updateById(existingEntity);
    }


    /**
     * 生成申请单号（yyyymmdd+3位流水码）
     */
    @Override
    public String generateApplicationNo() {
//        // 1. 获取当天日期
//        String datePart = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
//
//        // 2. 查询当天最大流水号
//        Integer maxSeq = accessApplicationMapper.selectMaxSeqByDate(LocalDate.now());
//        int nextSeq = (maxSeq == null) ? 1 : maxSeq + 1;
//
//        // 3. 格式化为3位数字
//        String seqPart = String.format("%03d", nextSeq);

        return generateBugCode();
    }

    @Override
    public int updateStatus(Long id,Integer status) {
        AccessApplication  application = getById(id);
        if(application == null){
            throw new RuntimeException("申请单不存在");
        }
        LambdaUpdateWrapper<AccessApplication> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(AccessApplication::getId,id)
            .set(AccessApplication::getStatus, status);
        return baseMapper.update(null,updateWrapper);
    }

    @Override
    public  List<Tree<Long>>selectAppIdTreeList(String userName) {
        LambdaQueryWrapper<AccessApplication> queryWrapper = new LambdaQueryWrapper<>();

        // 只有当userName不为null且不为空时才添加查询条件
        if (StringUtils.isNotBlank(userName)) {
            queryWrapper.eq(AccessApplication::getOutUserName, userName);
        } else {
            // 如果userName为空，返回空列表或者根据业务需求处理
            return Collections.emptyList();
        }

        // 执行查询获取列表
        List<AccessApplication> list = baseMapper.selectList(queryWrapper);

        // 使用Hutool的Tree工具转换
        return list.stream()
            .filter(app -> app.getId() != null)
            .map(app -> {
                Tree<Long> tree = new Tree<>();
                tree.setId(app.getId());
                tree.setName(app.getAppNo());
                tree.setWeight(0); // 设置权重
                return tree;
            })
            .collect(Collectors.toList());
    }

    @Override
    public List<OutsourcingPerson> getPersonListByAppId(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("申请单ID不能为空");
        }

        // 使用 OutsourcingPersonMapper 查询关联的外协人员列表
        return outsourcingPersonMapper.selectList(
            new LambdaQueryWrapper<OutsourcingPerson>()
                .eq(OutsourcingPerson::getAppId, id)
                .eq(OutsourcingPerson::getIsDeleted, 0) // 只查询未删除的记录
        );
    }

    @Override
    public void updateStatusByAppNo(String appNo, Integer status) {
        LambdaUpdateWrapper<AccessApplication> updateWrapper = new LambdaUpdateWrapper<>();
        if(status == 2){
            updateWrapper.eq(AccessApplication::getAppNo, appNo)
                        .set(AccessApplication::getStatus, status);
        }
        else if(status == 3) {
            updateWrapper.eq(AccessApplication::getAppNo, appNo)
                        .set(AccessApplication::getStatus, status);
//            deletePerson(appNo);
        }
        baseMapper.update(null, updateWrapper);
    }
    @Override
    public void sendMqMessage(String appNo){
        LambdaQueryWrapper<AccessApplication> queryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<AccessApplication> eq = queryWrapper.eq(AccessApplication::getAppNo, appNo);
        Long id = baseMapper.selectOne(eq).getId();
        LambdaQueryWrapper<OutsourcingPerson> queryWrapper2 = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<OutsourcingPerson> eq2 = queryWrapper2.eq(OutsourcingPerson::getAppId, id);
        List<OutsourcingPerson> personList = outsourcingPersonMapper.selectList(eq2);
        List<OutsourcingPersonMsgVO> voList = personList.stream().map(person -> {
            OutsourcingPersonMsgVO vo = new OutsourcingPersonMsgVO();
            // 复制相同属性
            BeanUtils.copyProperties(person, vo);

            // 设置额外属性
            String company = this.getById(person.getAppId()).getOutUnit();
            String area = this.getById(person.getAppId()).getArea();

            vo.setCompanyName(company);
            vo.setWorkArea(area);
            Long portraitPhotoId = null;
            if(person.getPortraitPhoto() != null) {
                portraitPhotoId = Long.parseLong(person.getPortraitPhoto());
                String url3 = sysOssService.getById(portraitPhotoId).getUrl();
                String replaceUrl3 = url3.replace("127.0.0.1", "192.168.110.168");
                vo.setFaceFile(replaceUrl3);
                vo.setPersonType("1");
                vo.setBeginTime(person.getEntryTime());
            }
            return vo;
        }).collect(Collectors.toList());

        HrMessage<OutsourcingPersonMsgVO> msg = new HrMessage<>(OutsourcingPerson.class.getSimpleName().toLowerCase(), "VS", "U", voList);
        String message = JsonUtils.toJsonString(msg);
        normalRabbitProducer.sendOutMqMessage(message);
    }

    @Override
    public void createQRCode(String name,String appNo, HttpServletResponse response) {
        try {
            // 生成二维码
            BufferedImage qrImage = QrCodeUtil.generate(
                "http://www.baidu.com/",
                300, 300
            );

            // 在二维码下方加文字
            int width = qrImage.getWidth();
            int height = qrImage.getHeight();
            // int extraHeight = 50; // 给文字留空间

            // 使用更高分辨率的图像
            BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = combined.createGraphics();

            // 设置高质量渲染提示
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);

            // 背景白色
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, width, height);

            // 画二维码
            g.drawImage(qrImage, 0, 0, null);

            // 设置文字样式
            // g.setColor(Color.BLACK);
            // g.setFont(new Font("楷体", Font.PLAIN, 40));

            // 文字居中
            // FontMetrics fm = g.getFontMetrics();
            // int textWidth = fm.stringWidth(name);
            // int x = (width - textWidth) / 2;
            // int y = height + (extraHeight + fm.getAscent()) / 2 - 15;

            // g.drawString(name, x, y);
            g.dispose();

            // 保存文件
//            ImageIO.write(combined, "jpg", new File("D:\\QRCode\\" + name + ".jpg"));
            // 设置响应头，触发浏览器下载
            response.setContentType("image/jpeg");
            response.setHeader("Content-Disposition", "attachment; filename=\"" +
                java.net.URLEncoder.encode(name, "UTF-8") + ".jpg\"");

            // 将图像写入响应输出流
            ImageIO.write(combined, "jpeg", response.getOutputStream());
            response.getOutputStream().flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    @Override
    public TableDataInfo<AccessApplication> appList(AccessApplication accessApplication, PageQuery pageQuery) {
        Page<AccessApplication> page = baseMapper.selectPageAccessApplicationList(pageQuery.build(), this.buildQueryWrapper(accessApplication));
        return TableDataInfo.build(page);
    }

    /**
     * 查询条件构建
     */
    private LambdaQueryWrapper<AccessApplication> buildQueryWrapper(AccessApplication accessApplication) {
        LambdaQueryWrapper<AccessApplication> queryWrapper = new LambdaQueryWrapper<>();

        // 基础条件：只查询未删除的记录
        queryWrapper.eq(AccessApplication::getIsDeleted, 0);

        // 添加各个查询条件
        queryWrapper
            .eq(accessApplication.getId() != null, AccessApplication::getId, accessApplication.getId())
            .eq(accessApplication.getAppNo() != null, AccessApplication::getAppNo, accessApplication.getAppNo())
            .like(StringUtils.isNotBlank(accessApplication.getAppUnit()), AccessApplication::getAppUnit, accessApplication.getAppUnit())
            .like(StringUtils.isNotBlank(accessApplication.getAppPerson()), AccessApplication::getAppPerson, accessApplication.getAppPerson())
            .like(StringUtils.isNotBlank(accessApplication.getOutContact()), AccessApplication::getOutContact, accessApplication.getOutContact())
            .like(StringUtils.isNotBlank(accessApplication.getOutUnit()), AccessApplication::getOutUnit, accessApplication.getOutUnit())
            .like(StringUtils.isNotBlank(accessApplication.getOutPhone()), AccessApplication::getOutPhone, accessApplication.getOutPhone())
            .eq(accessApplication.getAppDate() !=null,AccessApplication::getAppDate,accessApplication.getAppDate())
            .orderByDesc(AccessApplication::getAppDate);

        return queryWrapper;
    }

    /**
     * 分页查询
     */
    private Page<AccessApplication> queryApplicationPage(LambdaQueryWrapper<AccessApplication> queryWrapper,
                                                         int pageNum, int pageSize) {
        // 先查询总数
        long total = accessApplicationMapper.selectCount(queryWrapper);

        // 无数据时快速返回
        if (total == 0) {
            return new Page<>(pageNum, pageSize, total);
        }

        // 设置分页参数
        Page<AccessApplication> page = new Page<>(pageNum, pageSize, total);
        queryWrapper.last("LIMIT " + (pageNum - 1) * pageSize + "," + pageSize);

        // 执行查询
        List<AccessApplication> records = accessApplicationMapper.selectList(queryWrapper);
        page.setRecords(records);

        return page;
    }

    /**
     * 转换为VO
     */
    private AccessApplicationVO convertToVO(AccessApplication application) {
        AccessApplicationVO vo = new AccessApplicationVO();
        BeanUtils.copyProperties(application, vo);
        return vo;
    }



    public String generateBugCode() {
        String redisKey = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        long seq = RedisUtils.incrAtomicValue(redisKey);
        // 第一次自增时，设置过期（当天有效）
        if (seq == 1) {
            RedisUtils.expire(redisKey, Duration.ofDays(1));
        }

        return String.format("%s%03d", redisKey, seq);
    }

}
